#include "WeeklySchedule.h"


int WeeklySchedule::ENTRY_WIDTH = 10;

const Time WeeklySchedule::dummyTime = Time(-1,-1);
WeeklySchedule::WeeklySchedule(void){
	for(int day_i = 0; day_i < 7; ++day_i) {
		schedules[day_i] = new DailySchedule(intToDay(day_i+1));
	}
}
WeeklySchedule::~WeeklySchedule(void){
	for(int day_i = 0; day_i < 7; ++day_i) {
		delete schedules[day_i];
	}
}
bool WeeklySchedule::setAnAppointment(Time const & start, Time const & end, int day, string const & subject) 
{	
	Day dayTmp;
	try {
		dayTmp = intToDay(day);
	} catch (int){
		throw string("Illegal day.");
	}

	if(WeeklySchedule::setAnAppointment(new Appointment(start, end, dayTmp, subject)) == false) {
		throw string("Can't set an appoinment with overlaping time.");
	}
	return true;
}

bool WeeklySchedule::setAnAppointment(Appointment* app) 
{	
	return schedules[dayToInt(app->getDay())-1]->setAnAppointment(app);
}
Appointment* WeeklySchedule::removeAnAppointment(Time const & start, int day) {
	if(!(1 <= day && day <= 7)) {
		//FIXME throw something
		return false;
	}
	return schedules[day-1]->removeAnAppointment(start);
}

Appointment* WeeklySchedule::findAppointment(Time const & start, int day) const{
	if(!(1 <= day && day <= 7)) {
		//FIXME throw something
		return 0x0;
	}
	return schedules[day-1]->find(start);
}
bool WeeklySchedule::
	moveAppointment(
		Time const & startOrig, 
		int dayOrig, 
		Time const & startNew , 
		Time const & endNew , 
		int dayNew,
		string const & newSubject){
	Appointment* app = this->removeAnAppointment(startOrig, dayOrig);
	if (app == 0x0)
	{
		return false;
	}
	Time start = (startNew != dummyTime) ? startNew : startOrig;
	Time end = (endNew != dummyTime) ? endNew : app->getEndTime();
	Day day = (dayNew != -1) ? intToDay(dayNew) : intToDay(dayOrig); 
	string subject = (newSubject.compare("N/A") == 0)? app->getSubject() : newSubject; 
	if(this->setAnAppointment(start,end,day, subject) == false)
	{ 
		//recover
		this->setAnAppointment(app);
		throw string("Can't set appoinment.");
	}
	return true;

}

	/*
	init table head (days...);
	init an array of iterators (one per each day);
	while (not all iterators reached the end){
		obtain I - the minimal day-iterator;
		print I's start hour (formatted)
		foreach day itertor I':
			find if it conatins a meeting that falls within I's time span:
			if it does: print the meeting
			else: print a blank space
			advance I'
		advance I!
	}
	*/

void WeeklySchedule::printSchedule () const
{
	cout << setw((ENTRY_WIDTH/2) + 1) << ' ';
	for (int i = 1; i < 8; i++){
		cout << allign << intToDay(i);
	}
	cout << endl;

	std::set<Appointment*,fnCompareAppointment>::iterator arr[7];
	for (int i = 0; i < 7; i++){
		arr[i] = schedules[i]->meetings.begin();
	} 
	set<Appointment*,fnCompareAppointment>::iterator const *  min_itr_ptr;
	while ((min_itr_ptr = getMinDayIterator(arr))!=0)
	{
		Appointment* canidate = **min_itr_ptr;
		Time t = canidate->getStartTime();
		cout << t << " ";
		for (int i = 0; i < 7; i++){
			char fill = i%2 ? '#' : '$';
			canidate = schedules[i]->findAny(t);
			if (canidate != 0){
				if (canidate->getStartTime() == t)
				{
					if (canidate->getSubject().length() > ENTRY_WIDTH)
						cout << allign << setfill(fill) << "TOO LONG";
					else cout << allign << setfill(fill) << canidate->getSubject();
					arr[i]++;
				}
				else cout << allign << setfill(fill) << fill;	
			}
			else cout << allign << setfill('/') << '/';
		}
		//*min_itr_ptr++;
		cout << endl;
	}
}

set<Appointment*,fnCompareAppointment>::iterator const * 
	WeeklySchedule::getMinDayIterator(set<Appointment*,fnCompareAppointment>::iterator const * arr) const
{
	set<Appointment*,fnCompareAppointment>::iterator const *  min_itr_ptr = 0;
	for (int i=0; i < 7; i++){

		if  (arr[i] == schedules[i]->meetings.end()) continue;
		else
		{
			if (min_itr_ptr == 0 || (*arr[i])->getStartTime() < (**min_itr_ptr)->getStartTime())
			{
				min_itr_ptr = arr+i;
			}	
		}
	}
	return min_itr_ptr;
}


ostream& allign(ostream& os)
{
	return os << left << setw(WeeklySchedule::ENTRY_WIDTH) << setfill(' ');
}